海南老脚数

vuePress-theme-reco 海南老脚数    2017 - 2021
海南老脚数 海南老脚数

Choose mode

  • dark
  • auto
  • light
主页
指南
  • 应用介绍
  • cH5-PWA应用 (opens new window)
  • SSR-个人官网 (opens new window)
  • 微前端框架应用 (opens new window)
印记
高级
  • 小程序Node后端实践
  • JS开发灵活的数据应用
  • Node核心知识
  • Git原理详解及实战
进阶
  • 大厂H5开发实战
  • 前端性能优化
  • 前端面试指南
组件库
  • Vue3.0
  • Nuxt
  • 吃吃吃
分类
  • 问题集中营
  • VUE
  • 前端小笔记
  • Cookie
  • 深夜食堂
标签
Github (opens new window)
掘金 (opens new window)
author-avatar

海南老脚数

5

文章

4

标签

主页
指南
  • 应用介绍
  • cH5-PWA应用 (opens new window)
  • SSR-个人官网 (opens new window)
  • 微前端框架应用 (opens new window)
印记
高级
  • 小程序Node后端实践
  • JS开发灵活的数据应用
  • Node核心知识
  • Git原理详解及实战
进阶
  • 大厂H5开发实战
  • 前端性能优化
  • 前端面试指南
组件库
  • Vue3.0
  • Nuxt
  • 吃吃吃
分类
  • 问题集中营
  • VUE
  • 前端小笔记
  • Cookie
  • 深夜食堂
标签
Github (opens new window)
掘金 (opens new window)
  • 额外说点:.gitignore——排除不想被管理的文件和目录
  • 高级 1:不喜欢 merge 的分叉?用 rebase 吧
  • 高级 2:刚刚提交的代码,发现写错了怎么办?
  • 高级 3:写错的不是最新的提交,而是倒数第二个?
  • 高级 4:比错还错,想直接丢弃刚写的提交?
  • 高级 5:想丢弃的也不是最新的提交?
  • 高级 6:代码已经 push 上去了才发现写错?
  • 高级 7:reset 的本质——不止可以撤销提交
  • 高级 8:checkout 的本质
  • 高级 9:紧急情况:「立即给我打个包,现在马上!」
  • 高级 10:branch 删过了才想起来有用?
  • 进阶 1:HEAD、master 与 branch
  • 进阶 2:push 的本质
  • 进阶 3:merge:合并 commits
  • 进阶 4:Feature Branching:最流行的工作流
  • 进阶 5:关于 add
  • 进阶 6:看看我都改了什么
  • 上手 1:新公司用 Git 管理代码,怎么快速上手?
  • 上手 2:团队工作的基本工作模型
  • 什么是分布式版本控制系统(DVCS)
  • 什么是版本控制系统(VCS)
  • 总结

vuePress-theme-reco 海南老脚数    2017 - 2021

高级 7:reset 的本质——不止可以撤销提交

海南老脚数

# 高级 7:reset 的本质——不止可以撤销提交

前面讲到,在最新的 commit 写错时,可以用 reset --hard 来把 commit 撤销:

git reset --hard HEAD^

1
2

用这行代码可以撤销掉当前 commit

在这节里,就对 reset 多说点,说说它的本质,说说它在撤销提交之外的用途。

# reset 的本质:移动 HEAD 以及它所指向的 branch

实质上,reset 这个指令虽然可以用来撤销 commit ,但它的实质行为并不是撤销,而是移动 HEAD ,并且「捎带」上 HEAD 所指向的 branch(如果有的话)。也就是说,reset 这个指令的行为其实和它的字面意思 "reset"(重置)十分相符:它是用来重置 HEAD 以及它所指向的 branch 的位置的。

而 reset --hard HEAD^ 之所以起到了撤销 commit 的效果,是因为它把 HEAD 和它所指向的 branch 一起移动到了当前 commit 的父 commit 上,从而起到了「撤销」的效果:

Git 的历史只能往回看,不能向未来看,所以把 HEAD 和 branch 往回移动,就能起到撤回 commit 的效果。

所以同理,reset --hard 不仅可以撤销提交,还可以用来把 HEAD 和 branch 移动到其他的任何地方。

git reset --hard branch2

1
2

不过……reset 后面总是跟着的那个 --hard 是什么意思呢?

reset 指令可以重置 HEAD 和 branch 的位置,不过在重置它们的同时,对工作目录可以选择不同的操作,而对工作目录的操作的不同,就是通过 reset 后面跟的参数来确定的。

# reset --hard:重置工作目录

reset --hard 会在重置 HEAD 和 branch 的同时,重置工作目录里的内容。当你在 reset 后面加了 --hard 参数时,你的工作目录里的内容会被完全重置为和 HEAD 的新位置相同的内容。换句话说,就是你的未提交的修改会被全部擦掉。

例如你在上次 commit 之后又对文件做了一些改动:

git status

1
2

然后,你执行了 reset 并附上了 --hard 参数:

git reset --hard HEAD^

1
2

你的 HEAD 和当前 branch 切到上一条 commit 的同时,你工作目录里的新改动也一起全都消失了,不管它们是否被放进暂存区:

git status

1
2

可以看到,在 reset --hard 后,所有的改动都被擦掉了。

# reset --soft:保留工作目录

reset --soft 会在重置 HEAD 和 branch 时,保留工作目录和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区。

什么是「重置 HEAD 所带来的新的差异」?就是这里:

由于 HEAD 从 4 移动到了 3,而且在 reset 的过程中工作目录的内容没有被清理掉,所以 4 中的改动在 reset 后就也成了工作目录新增的「工作目录和 HEAD 的差异」。这就是上面一段中所说的「重置 HEAD 所带来的差异」。

所以在同样的情况下:

git status

1
2

假设此时当前 commit 的改动内容是新增了 laughters.txt 文件:

git show --stat

1
2

如果这时你执行:

git reset --soft HEAD^

1
2

那么除了 HEAD 和它所指向的 branch1 被移动到 HEAD^ 之外,原先 HEAD 处 commit 的改动(也就是那个 laughters.txt 文件)也会被放进暂存区:

git status

1
2

这就是 --soft 和 --hard 的区别:--hard 会清空工作目录的改动,而 --soft 则会保留工作目录的内容,并把因为保留工作目录内容所带来的新的文件差异放进暂存区。

# reset 不加参数:保留工作目录,并清空暂存区

reset 如果不加参数,那么默认使用 --mixed 参数。它的行为是:保留工作目录,并且清空暂存区。也就是说,工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录。简而言之,就是「把所有差异都混合(mixed)放在工作目录中」。

还以同样的情况为例:

git status

1
2

修改了 games.txt 和 shopping list.txt,并把 games.txt 放进了暂存区。

git show --stat

1
2

最新的 commit 中新增了 laughters.txt 文件。

这时如果你执行无参数的 reset:

git reset HEAD^

1
2

工作目录的内容和 --soft 一样会被保留,但和 --soft 的区别在于,它会把暂存区清空:

git status

1
2

# 小结

本节内容讲了 reset 指令的本质:重置 HEAD 以及它所指向的 branch 的位置。同时,介绍了 reset 的三种参数:

  1. --hard:重置位置的同时,清空工作目录的所有改动;
  2. --soft:重置位置的同时,保留工作目录和暂存区的内容,并把重置 HEAD 的位置所导致的新的文件差异放进暂存区。
  3. --mixed(默认):重置位置的同时,保留工作目录的内容,并清空暂存区。

除了上面这三种参数,还有一些没有列出的较为不常用的参数;另外除了我讲的功能外,reset 其实也还有一些别的功能和用法。不过 reset 最关键的功能、用法和本质原理就是上面这些了,想了解更多的话,可以去官网了解一下。

欢迎来到 海南老脚数
看板娘